﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Tszy.Unlimited.Data.AdoNet.Sql.Components.Expressions.Values.Handlers
{
    internal class DefaultValueExpressionHandler : ValueExpressionHandlerBase
    {
        public override ValueExpressionResult Handler(ExpressionContext context, Expression expression)
        {
            switch (expression.NodeType)
            {
                case ExpressionType.Convert:
                    var unaryExpression = expression as UnaryExpression;

                    return Handler(context, unaryExpression?.Operand);

                case ExpressionType.ArrayIndex:
                    //数组。
                    var arrayIndexParameterValue = Evaluator.Eval(expression);

                    return new ValueExpressionResult
                    {
                        Status = true,
                        Type = ValueExpressionType.Value,
                        PropertyType = expression.Type,
                        Value = arrayIndexParameterValue
                    };

                case ExpressionType.NewArrayInit:
                    //数组。
                    var newArrayInitParameterValue = Evaluator.Eval(expression);

                    return new ValueExpressionResult
                    {
                        Status = true,
                        Type = ValueExpressionType.Value,
                        PropertyType = expression.Type,
                        Value = newArrayInitParameterValue
                    };

                case ExpressionType.Constant:

                    //参数常量值。
                    var constantExpression = expression as ConstantExpression;

                    return new ValueExpressionResult
                    {
                        Status = true,
                        Type = ValueExpressionType.Value,
                        PropertyType = constantExpression?.Type,
                        Value = constantExpression?.Value
                    };

                case ExpressionType.MemberAccess:
                    //变量。
                    var memberExpression = expression as MemberExpression;

                    var member = memberExpression?.Member;

                    if (member == null)
                        return new ValueExpressionResult { Status = false };

                    var parameterExpression = memberExpression.Expression as ParameterExpression;

                    //如果与参数类型相同，则表示是参数信息，则取参数名即可。
                    if (parameterExpression != null)
                    {
                        return new ValueExpressionResult
                        {
                            Status = true,
                            Type = ValueExpressionType.Parameter,
                            Expression = parameterExpression,
                            PropertyType = memberExpression.Type,
                            Value = memberExpression.Member.Name
                        };
                    }

                    var value = Evaluator.Eval(expression);

                    return new ValueExpressionResult
                    {
                        Status = true,
                        Type = ValueExpressionType.Value,
                        PropertyType = expression.Type,
                        Value = value
                    };

                case ExpressionType.Parameter:
                    //参数名。
                    var parameterInfoExpression = expression as ParameterExpression;

                    return new ValueExpressionResult
                    {
                        Status = true,
                        Type = ValueExpressionType.Parameter,
                        Expression = parameterInfoExpression,
                        Value = parameterInfoExpression?.Name
                    };

                case ExpressionType.MemberInit:
                    var memberInitExpression = expression as MemberInitExpression;

                    if (memberInitExpression != null && memberInitExpression.Bindings.Any())
                    {
                        var list = new List<ExpressionParameter>();

                        foreach (var newMember in memberInitExpression.Bindings)
                        {
                            var parameterName = string.Empty;
                            var memberName = string.Empty;
                            //var parameterType = memberInitExpression.Type;
                            //var isParameter = true;

                            switch (newMember.BindingType)
                            {
                                case MemberBindingType.Assignment:
                                    var tmpMember1 = (MemberAssignment)newMember;
                                    var parameterResult1 = Handler(context, tmpMember1.Expression);
                                    memberName = tmpMember1.Member.Name;
                                    parameterName = $"{parameterResult1.Value}";

                                    //if (parameterResult1.Expression != null)
                                    //{
                                    //    parameterType = parameterResult1.Expression.Type;
                                    //}
                                    //else
                                    //{
                                    //    isParameter = false;
                                    //    //parameterName = $"{ParameterManager.Instance.GetParameterValue(context, parameterName, newMember.Member.Name)}";
                                    //}

                                    break;

                                case MemberBindingType.MemberBinding:
                                    //var tmpMember2 = (MemberMemberBinding)newMember;
                                    break;

                                case MemberBindingType.ListBinding:
                                    //var tmpMember3 = (MemberListBinding)newMember;
                                    break;

                                default:
                                    break;
                            }

                            //if (isParameter)
                            //{
                            //    parameterName = ParameterManager.Instance.GetParameterName(context, parameterType, parameterName, newMember.Member.Name);
                            //}

                            if (!string.IsNullOrWhiteSpace(parameterName))
                                list.Add(new ExpressionParameter { Name = parameterName, Alias = memberName });
                        }

                        return new ValueExpressionResult
                        {
                            Status = true,
                            Type = ValueExpressionType.Parameter,
                            Expression = memberInitExpression,
                            Value = list
                        };
                    }

                    break;

                case ExpressionType.Not:
                    var notExpression = expression as UnaryExpression;

                    var notMemberExpression = notExpression.Operand as MemberExpression;

                    return Handler(context, notMemberExpression);

                case ExpressionType.New:

                    var newExpression = expression as NewExpression;

                    if (newExpression == null)
                        throw new ArgumentNullException(nameof(newExpression));

                    if (!newExpression.Members.Any())
                        throw new ArgumentNullException(nameof(newExpression));

                    if (newExpression.Arguments.Count > 0)
                    {
                        var list = new List<ExpressionParameter>();

                        for (var index = 0; index < newExpression.Arguments.Count; index++)
                        {
                            var newParameter = Handler(context, newExpression.Arguments[index]);
                            var newMember = newExpression.Members[index];

                            if (newParameter != null)
                            {
                                var paramenterName = $"{newParameter?.Value}";

                                if (!string.IsNullOrWhiteSpace(paramenterName))
                                    list.Add(new ExpressionParameter { Name = paramenterName, Alias = newMember.Name });
                            }
                        }

                        return new ValueExpressionResult
                        {
                            Status = true,
                            Type = ValueExpressionType.Parameter,
                            Expression = newExpression,
                            Value = list
                        };
                    }

                    break;

                case ExpressionType.Call:
                    var callExpression = expression as MethodCallExpression;

                    if (callExpression == null)
                        return new ValueExpressionResult { Status = true };

                    var expressionValue = Evaluator.Eval(callExpression);

                    return new ValueExpressionResult
                    {
                        Status = true,
                        Type = ValueExpressionType.Value,
                        PropertyType = callExpression.Type,
                        Value = expressionValue
                    };
            }

            return ResultError();
        }
    }
}